package com.example.androidexample.qr;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import androidx.annotation.Nullable;
import androidx.core.graphics.PathParser;

public class QRView extends View {

    private Paint cornerPaint;
    private Rect identificationRect;
    private ValueAnimator animator;
    private Paint maskPaint;
    private int cornerWidth;
    private float scale;
    private Path cornerPath;
    private Paint scanLinePain;

    public QRView(Context context) {
        super(context);
    }

    public QRView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public QRView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private int mWidth;
    private int mHeight;
    private static final int MASK_ALPHA = 0x80;
    private static final long ANIMATOR_DURATION = 4000L;
    private static final int BASE_PATH_UNIT = 36;
    private static final String TAG = "QRView";
    private static final String BASE_CORNER_STR = "M2,36 a2,2 0,0 1,-2 -2 L0,11.058A11.07,11.07 0,0 1,11.058 0L34,0a2,2 0,0 1,0 4L11.058,4A7.066,7.066 0,0 0,4 11.058L4,34A2,2 0,0 1,2 36Z";
    private int scanWidth,scanHeight;
    private int scanLineY;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mHeight = h;
        mWidth = w;

        Log.d(TAG, "onSizeChanged: ");
        init();
    }

    private void init() {
        cornerPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        cornerPaint.setColor(Color.WHITE);
        cornerPaint.setStyle(Paint.Style.FILL);
        cornerPaint.setStrokeWidth(1f);

        maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        maskPaint.setColor(Color.BLACK);
        maskPaint.setAlpha(MASK_ALPHA);

        scanWidth = Math.min(mHeight,mWidth) / 2;
        scanHeight = scanWidth;

        //扫码矩形
        identificationRect = new Rect((mWidth - scanWidth)/2,(mHeight - scanHeight)/2 - mHeight/10, (mWidth - scanWidth)/2 + scanWidth,(mHeight - scanHeight)/2 - mHeight/10 + scanHeight);

        scanLinePain = new Paint();
        scanLinePain.setStrokeWidth(dpToPxFloat(2f));
        scanLinePain.setAntiAlias(true);
        scanLinePain.setStyle(Paint.Style.FILL);
        scanLinePain.setShader(new LinearGradient(identificationRect.left,0f,identificationRect.right,0f,
                new int[]{0x00157EE6, -0xe95001, 0x00157EE6},new float[]{0f, 0.5f, 1f}, Shader.TileMode.CLAMP));

        initAnimator();

        cornerWidth = dpToPxInt(2);
        scale = dpToPxFloat(18) / BASE_PATH_UNIT;
        cornerPath = PathParser.createPathFromPathData(BASE_CORNER_STR);
        Log.d(TAG, "init: ");

        startScan();

    }

    private int dpToPxInt(int dp){
        return (int)(dp * Resources.getSystem().getDisplayMetrics().density + 0.5f);
    }

    private float dpToPxFloat(float dp){
        return dp * Resources.getSystem().getDisplayMetrics().density + 0.5f;
    }

    private void initAnimator() {
        animator = ValueAnimator.ofInt(identificationRect.top,identificationRect.bottom);
        animator.setDuration(ANIMATOR_DURATION);
        animator.setInterpolator(new DecelerateInterpolator());
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scanLineY = (int) animation.getAnimatedValue();
                postInvalidate(identificationRect.left, identificationRect.top, identificationRect.right,
                        identificationRect.bottom);
            }
        });
    }

    public void startScan() {
        Log.d(TAG, "startScan: ");
        if (animator != null) {
            animator.start();
        }

    }

    public void stopScan() {
        animator.cancel();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawMask(canvas);
        drawCorner(canvas);
        drawScanLine(canvas);
    }

    private void drawScanLine(Canvas canvas) {
        if (scanLineY == 0) {
            return;
        }

        canvas.drawLine(identificationRect.left,scanLineY,identificationRect.right,scanLineY,scanLinePain);
    }

    private void drawCorner(Canvas canvas) {
        //左上
        drawCornerPath(canvas,cornerPaint,scale,0f,identificationRect.left - cornerWidth,
                identificationRect.top - cornerWidth);
        //右上
        drawCornerPath(canvas,cornerPaint,scale,90f,identificationRect.right + cornerWidth,
                identificationRect.top - cornerWidth);
        //右下
        drawCornerPath(canvas,cornerPaint,scale,180f,identificationRect.right  + cornerWidth,
                identificationRect.bottom + cornerWidth);
        //左下
        drawCornerPath(canvas,cornerPaint,scale,270f,identificationRect.left - cornerWidth,
                identificationRect.bottom + cornerWidth);


    }

    private void drawCornerPath(Canvas canvas,Paint paint,float scale,float degree,float translateX,float translateY) {
        canvas.save();
        canvas.translate(translateX, translateY);
        canvas.scale(scale, scale);
        canvas.rotate(degree);
        canvas.drawPath(cornerPath, paint);
        canvas.restore();
    }

    private void drawMask(Canvas canvas) {
        canvas.drawRect(0f,0f,mWidth,identificationRect.top,maskPaint);
        canvas.drawRect(identificationRect.right,identificationRect.top,mWidth,identificationRect.bottom,maskPaint);
        canvas.drawRect(0f,identificationRect.bottom,mWidth,mHeight,maskPaint);
        canvas.drawRect(0f,identificationRect.top,identificationRect.left,identificationRect.bottom,maskPaint);
    }
}
